package
{
	import com.adobe.utils.AGALMiniAssembler;
	import com.adobe.utils.PerspectiveMatrix3D;
	
	import flash.display.*;
	import flash.display3D.*;
	import flash.display3D.textures.*;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	import flash.utils.getTimer;

	
	
	[SWF(width=550,height=400,frameRate=60,backgroundColor=0x000000)]
	
	public class Stage3d_triangle extends Sprite
	{
		private var context3d:Context3D;
		private var indexData:Vector.<uint>;
		private var vertexData:Vector.<Number>;
		private var vertexBuffer:VertexBuffer3D;
		private var indexBuffer:IndexBuffer3D;
		private var vertexShader:AGALMiniAssembler;
		private var fragmentShader:AGALMiniAssembler;
		private var texture:Texture;
		private var model3D:Matrix3D=new Matrix3D();
		private var view3D:Matrix3D=new Matrix3D();
		private var modelView3D:Matrix3D=new Matrix3D();
		private var projection3D:PerspectiveMatrix3D=new PerspectiveMatrix3D();
		private var shader:Program3D;
		private var t:Number=0;
		private var str:String;
		
		[Embed(source="BlueTownv2_byLunarea.png")]
		private var textureBitmap:Class;
		private var triangleTextureBitmap:Bitmap=new textureBitmap();
		
		public function Stage3d_triangle()
		{
			if (stage != null){
				init();
			    str=String.fromCharCode(35);
				trace(str);
			}else 
				addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init():void{
			if (hasEventListener(Event.ADDED_TO_STAGE))
				removeEventListener(Event.ADDED_TO_STAGE, init);
			
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			
			// and request a context3D from Stage3d
			stage.stage3Ds[0].addEventListener(
				Event.CONTEXT3D_CREATE, onContext3dCreate);
			stage.stage3Ds[0].requestContext3D();
		}
		
		private function onContext3dCreate(evt:Event):void{
			if (hasEventListener(Event.ENTER_FRAME))
				removeEventListener(Event.ENTER_FRAME,onEnterFrame);
			
			var s3d:Stage3D=evt.target as Stage3D;
			context3d=s3d.context3D;
			
			if (context3d == null) 
			{
				// Currently no 3d context is available (error!)
				return;
			}
			context3d.enableErrorChecking = true;
			
			initData();
			
			context3d.configureBackBuffer(550,400,0,true);
			
			vertexShader=new AGALMiniAssembler();
			vertexShader.assemble(Context3DProgramType.VERTEX,
//				"dp4 op.x, va0, vc0		\n" +	// 4x4 matrix transform from stream 0 to output clipspace
//				"dp4 op.y, va0, vc1		\n" +
//				"dp4 op.z, va0, vc2		\n" +
//				"dp4 op.w, va0, vc3		\n" +
//				"mov v0, va1.xyzw		\n"
				
				"m44 op va0,vc0\n"+
				"mov v0,va0\n"+
				"mov v1,va1\n"+
				"mov v2,va2\n"
				
			);
			
			fragmentShader=new AGALMiniAssembler();
			fragmentShader.assemble(Context3DProgramType.FRAGMENT,
				//only use vertex color
//				"mov oc, v2\n"
//				using texture sampler
				"tex ft1,v1,fs0<2d,linear,nomip>\n"+
				"mov oc,ft1\n"
			)
			
			shader=context3d.createProgram();
			shader.upload(vertexShader.agalcode,fragmentShader.agalcode);
			
			vertexBuffer=context3d.createVertexBuffer(3,9);
			vertexBuffer.uploadFromVector(vertexData,0,3);
			
			indexBuffer=context3d.createIndexBuffer(3);
			indexBuffer.uploadFromVector(indexData,0,indexData.length);
			
			//if no texture, comment these two lines.
			texture=context3d.createTexture(512,512,Context3DTextureFormat.BGRA,false);
			uploadTextureWithMipmaps(texture,triangleTextureBitmap.bitmapData);
			
			//包含Z轴透视效果
//			view3D.identity();
//			view3D.appendTranslation(0,0,2);
//			
//			projection3D.identity();
//			projection3D.perspectiveFieldOfViewRH(45.0, 1.5, 0.01, 100.0);
				
			addEventListener(Event.ENTER_FRAME,onEnterFrame);
			
		}
		
		private function on3dCreateError(evt:ErrorEvent):void{
			trace("Context3d can not be created!");
		}
		
		private function onEnterFrame(evt:Event):void{
			context3d.clear(0,0,0);
			
//			t+=2.0;
			//using texture
			context3d.setTextureAt(0,texture);
			//no texture
//			context3d.setTextureAt(0,null);
			context3d.setProgram(shader);
			
			model3D.identity();
			model3D.appendRotation(getTimer()/50,Vector3D.Z_AXIS);
			
//			modelView3D.identity();
//			modelView3D.append(model3D);
//			modelView3D.append(view3D);
//			modelView3D.append(projection3D);
			
			context3d.setProgramConstantsFromMatrix(
				Context3DProgramType.VERTEX,
				0, model3D, true );
			context3d.setVertexBufferAt(0,vertexBuffer,0,Context3DVertexBufferFormat.FLOAT_2);
			context3d.setVertexBufferAt(1,vertexBuffer,5,Context3DVertexBufferFormat.FLOAT_3);
			context3d.setVertexBufferAt(2,vertexBuffer,5,Context3DVertexBufferFormat.FLOAT_4);

			
			context3d.drawTriangles(indexBuffer);
			context3d.present();
		}
		
		private function uploadTextureWithMipmaps(dest:Texture, src:BitmapData):void
		{
			var ws:int = src.width;
			var hs:int = src.height;
			var level:int = 0;
			var tmp:BitmapData;
			var transform:Matrix = new Matrix();
			
			tmp = new BitmapData(src.width, src.height, true, 0x00000000);
			
			while ( ws >= 1 && hs >= 1 )
			{ 
				tmp.draw(src, transform, null, null, null, true); 
				dest.uploadFromBitmapData(tmp, level);
				transform.scale(0.5, 0.5);
				level++;
				ws /=2;
				hs /=2;
				if (hs && ws) 
				{
					tmp.dispose();
					tmp = new BitmapData(ws, hs, true, 0x00000000);
				}
			}
			tmp.dispose();
		}
		
		private function initData():void{
			indexData=Vector.<uint>(
				[0,1,2]	
			);
			vertexData=Vector.<Number>(
				[
					//x,y,z,u,v,r,g,b,a
					-0.5,-0.5,0,0,0,1,0,0,1,
					-0.5,0.5,0,0,1,0,1,0,1,
					0.5,-0.5,0,1,0,0,0,1,1
				]
			);
		}
		
	}
}